#include "testbedGL.hpp"
#include <boost/thread.hpp>
#include <dae.h>
#include <dom/domCOLLADA.h>
#include "collada_GL.hpp"


TestbedGL::Window *window;
Quat quat;
Vector3 position;

TestbedGL::Scene scene;

Vector3 view;
using namespace  Vectormath::Aos;
Matrix3 mat;
using namespace TestbedGL;
Matrix4GL modelview,projection2;

Texture *tex,*bex,*depth;
RenderTarget *rt;
GLuint img;
Shader* shader;
ShaderVariable *mdlmtx,*prjmtx,*tex1,*tex2,*object,*eyePos;
ShaderAttribute *normals,*binormals,*tangents;

static void quit_program( int code )
{
    SDL_Quit( );
    exit( code );
}





static void process_events( void )
{

    SDL_Event event;
    while ( SDL_PollEvent( &event ) )
    {

        int x,y;
        float fx = x;
        float fy = y;
        static float xx = 0;
        static float yy = 0;
        //Matrix4 mat;
        TestbedGL::Matrix4GL mat;
        switch ( event.type )
        {
        case SDL_MOUSEMOTION:


            SDL_GetRelativeMouseState(&x, &y);
            fx = (float)x/(3.141*180);
            fy = (float)y/(3.141*180);
            xx +=fx;
            yy +=fy;
            mat = TestbedGL::Euler2Quat(xx,0,yy);
            view = Vector3(mat.getElem(0,2),mat.getElem(1,2),mat.getElem(2,2));
            view = normalize(view);
            modelview = Matrix4::lookAt(Point3(position),Point3(position+view),Vector3(0,1.0,0));
            break;

            // mouse down handler
        case SDL_MOUSEBUTTONDOWN:
            break;

            // mouse up handler
        case SDL_MOUSEBUTTONUP:
            break;

        case SDL_KEYDOWN:
            if (event.key.keysym.sym == SDLK_ESCAPE)
            {
                quit_program(0);
            }
            if (event.key.keysym.sym == SDLK_UP)
            {

                position+=view;
                modelview = Matrix4::lookAt(Point3(position),Point3(position+view),Vector3(0,1.0,0));

            }
            if (event.key.keysym.sym == SDLK_DOWN)
            {
                position-=view;
                modelview = Matrix4::lookAt(Point3(position),Point3(position+view),Vector3(0,1.0,0));

            }

            if (event.key.keysym.sym == SDLK_RIGHT)
            {

                position+=cross(view,Vector3(0,1,0));
                modelview = Matrix4::lookAt(Point3(position),Point3(position+view),Vector3(0,1.0,0));
            }

            if (event.key.keysym.sym == SDLK_LEFT)
            {

                position-=cross(view,Vector3(0,1,0));
                modelview = Matrix4::lookAt(Point3(position),Point3(position+view),Vector3(0,1.0,0));

            }

            break;
        case SDL_QUIT:
            /* Handle quit requests (like Ctrl-c). */
            quit_program( 0 );
            break;
        }

    }
}


void triangle()
{
    glEnable(GL_DEPTH_TEST);
// glLoadIdentity();

    //  rt->bind();

    //glClearColor(1.0,0.0,0.0,0.0);
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glEnable(GL_TEXTURE);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,bex->handler);
    glActiveTexture(GL_TEXTURE1);
    glEnable(GL_TEXTURE);
    glBindBuffer(GL_TEXTURE_2D,tex->handler);
    shader->Bind();

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    static float rot = 0;
    rot+=0.01;
    for (int i = 0; i < scene.nodes.size(); i++)
    {
        Matrix4GL tmp = modelview *scene.nodes[i].base_matrix;
        mdlmtx->PassMatrix(tmp);
        prjmtx->PassMatrix(projection2);
        tmp =  scene.nodes[i].base_matrix;
        //tmp = inverse(tmp);
        object->PassMatrix(tmp);

        //glEnabletVertexAttribArrayARB(binormals->location);
        //glEnabletVertexAttribArrayARB(tangents->location);
        for (int j = 0; j < scene.nodes[i].geometry_ids.size(); j++)
        {
            scene.geometries[scene.nodes[i].geometry_ids[j]].bind();
            //printf("%d\n"d,node->geometries[0]->faces.size);
            //
            //        glVertexPointer(3,GL_FLOAT,0,meshes[0].inputs[0].array.get());
            //        glNormalPointer(GL_FLOAT,0,meshes[0].inputs[1].array.get());

            glDrawElements( GL_TRIANGLES, scene.geometries[scene.nodes[i].geometry_ids[j]].faces.size, GL_UNSIGNED_INT, scene.geometries[scene.nodes[i].geometry_ids[j]].faces.array.get());
        }
    }
    Matrix4GL identity = Matrix4::identity();

    mdlmtx->PassMatrix(identity);
    prjmtx->PassMatrix(projection2);
    glEnable(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D,tex->handler);
    glGenerateMipmapEXT(GL_TEXTURE_2D);
    glBegin(GL_QUADS);
    glVertex2f(0,0);
    glNormal3f(0,0,1.0);
    glTexCoord2f(0,0);

    glVertex2f(1,0);
    glNormal3f(0,0,1.0);
    glTexCoord2f(0,1);

    glVertex2f(1,1);
    glNormal3f(0,0,1.0);
    glTexCoord2f(1,1);

    glVertex2f(0,1);
    glNormal3f(0,0,1.0);
    glTexCoord2f(1,0);
    glEnd();
    glBindTexture(GL_TEXTURE_2D,0);
    //modelview= tmp;

}



char *data;
#ifdef WIN32
#include <windows.h>
int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
#else
int main(int argc, const char **params)
#endif
{
    window = new TestbedGL::Window(1024,768,24);

    window->SetRenderViewport(1024,768,55.0,1.0,10000.0);

    window->drawFrameFunc = triangle;

    DAE dae;

    COLLADA_GL::Scene scn;

    try
    {
        domCOLLADA* daedom = dae.open("i5.dae");
        scn = COLLADA_GL::ParseScene(daedom);
    }
    catch (const char *str)
    {
        std::cout << str <<std::endl;
    }
    for (int i = 0; i < scn.geometries.size(); i++)
    {
        if (scn.geometries[i].count==0) continue;
        shared_ptr<Geometry> geom(new Geometry());
        geom->name = scn.geometries[i].name;
        FloatArray pos(scn.geometries[i].inputs[0].width,scn.geometries[i].inputs[0].size,scn.geometries[i].inputs[0].width,scn.geometries[i].inputs[0].array,"positions");
        FloatArray norms(scn.geometries[i].inputs[1].width,scn.geometries[i].inputs[1].size,scn.geometries[i].inputs[1].width,scn.geometries[i].inputs[1].array,"normalss");
        //printf("%s\n",scn.geometries[i].inputs[1].name.c_str());
        // FloatArray tex_coord(scn.geometries[i].inputs[2].width,scn.geometries[i].inputs[2].size,scn.geometries[i].inputs[2].width,scn.geometries[i].inputs[2].array,"tex_coords");

        geom->link.set_vertex_array(pos);
        //geom->link.add_tex_coord_array(tex_coord);
        geom->link.set_normal_array(norms);
        //printf("%d\n",scn.geometries[i].count);
        shared_array<unsigned int> indc(new unsigned int[scn.geometries[i].count]);
        for (unsigned int sz = 0; sz < scn.geometries[i].count; sz++)
            indc[sz] = scn.geometries[i].indecies[sz];

        FaceArray faces(scn.geometries[i].count,indc);
        geom->faces = faces;
        scene.geometries.push_back(*geom);
    }

    for (int i = 0; i < scn.nodes.size(); i++)
    {
        scene.nodes.push_back(SceneNode());
        scene.nodes.rbegin()->base_matrix = scn.nodes[i].matrix;
        for (int j = 0; j < scn.nodes[i].geometry_urls.size(); j++)
        {
            //int id = scene.Geom(scn.nodes[i].geometry_urls[j].name);
            // if(scn.geometries[id].count>0)
            scene.nodes.rbegin()->geometry_ids.push_back(scene.Geom(scn.nodes[i].geometry_urls[j].name));
        }
        //scene.nodes.rbegin()->
    }
    //printf("GEOMETRY LOADED\n");

    //node->base_matrix = Matrix4GL::identity();
    modelview = Matrix4::translation(Vector3(0,0,1.0));

    projection2 = Matrix4::perspective(50.0/180*3.14159,1024.0/768.0,0.1,1000);
    glLoadMatrixf(projection2.getMatrix());


    tex = new Texture();
    tex->loadimage("bump2.tga");

    //depth = new Texture();
    //depth->build("GL_DEPTH_COMPONENT",256,256,0,false);
    //rt = new RenderTarget(256,256,*tex,*depth);

    bex = new Texture();
    bex->loadimage("bump1.tga");
    //Loading shader
    shader = new Shader("shader.vs","shader.fs");
    prjmtx = new ShaderVariable(*shader,"projection");
    mdlmtx = new ShaderVariable(*shader,"modelview");
    object = new ShaderVariable(*shader,"object");
//    eyePos = new ShaderVariable(*shader,"Eye");
//
//    tex1 = new ShaderVariable(*shader,"texture");
////    tex2 = new ShaderVariable(*shader,"texture2");
//    binormals = new ShaderAttribute(*shader,"binormal");
//    tangents = new ShaderAttribute(*shader,"tangent");


//    node->geometries[0]->link.arrays[3].id = binormals->location;
//    node->geometries[0]->link.arrays[4].id = tangents->location;


//    std::cout << node->children[0].geometries[0].icount;
    while (1)
    {
        window->DrawFrame();
        process_events( );

    }
    return 0;
}
